from __future__ import annotations

import random
from datetime import datetime, timezone

from fastapi import APIRouter, Depends, HTTPException, Query
from sqlalchemy import or_, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.api.response import success_response
from app.api.deps import get_current_user, get_db
from app.models.decision_preset import DecisionPreset
from app.models.user import User
from app.schemas import decision as decision_schema

router = APIRouter()

sys_random = random.SystemRandom()


def _normalize_options(options: list[str]) -> list[str]:
  normalized = []
  for raw in options:
    if not isinstance(raw, str):
      continue
    text = raw.strip()
    if text:
      normalized.append(text)
  deduped: list[str] = []
  seen = set()
  for item in normalized:
    key = item.lower()
    if key not in seen:
      deduped.append(item)
      seen.add(key)
  return deduped


def _ensure_access(preset: DecisionPreset | None, user: User) -> DecisionPreset:
  if not preset or preset.deleted_at is not None:
    raise HTTPException(status_code=404, detail="未找到指定的转盘")
  if preset.user_id != user.id and (user.active_relationship_id is None or preset.relationship_id != user.active_relationship_id):
    raise HTTPException(status_code=403, detail="没有权限访问该转盘")
  return preset


@router.get('', summary="列出已保存的随机转盘")
async def list_presets(
  limit: int = Query(default=20, ge=1, le=50),
  offset: int = Query(default=0, ge=0),
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
):
  conditions = [DecisionPreset.deleted_at.is_(None)]
  rel_id = current_user.active_relationship_id
  scope = DecisionPreset.user_id == current_user.id
  if rel_id:
    scope = or_(scope, DecisionPreset.relationship_id == rel_id)
  conditions.append(scope)

  stmt = (
    select(DecisionPreset)
    .where(*conditions)
    .order_by(DecisionPreset.updated_at.desc())
    .offset(offset)
    .limit(limit)
  )
  result = await session.scalars(stmt)
  presets = result.all()
  payload = [
    decision_schema.DecisionPresetResponse(
      id=p.id,
      title=p.title,
      options=p.options_json or [],
      style=p.style,
      is_shared=p.is_shared,
      color_seed=p.color_seed,
      usage_count=p.usage_count,
      last_used_at=p.last_used_at,
      last_result=p.last_result,
      created_at=p.created_at,
      updated_at=p.updated_at,
    )
    for p in presets
  ]
  return success_response({'items': payload, 'offset': offset, 'limit': limit})


@router.post('', summary="创建随机转盘")
async def create_preset(
  payload: decision_schema.DecisionPresetCreate,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
):
  options = _normalize_options(payload.options)
  if len(options) < 2:
    raise HTTPException(status_code=422, detail="请至少提供两个不同的选项")
  if len(options) > 8:
    raise HTTPException(status_code=422, detail="选项数量最多 8 个")

  relationship_id = None
  is_shared = payload.is_shared and current_user.active_relationship_id is not None
  if is_shared:
    relationship_id = current_user.active_relationship_id

  preset = DecisionPreset(
    user_id=current_user.id,
    relationship_id=relationship_id,
    title=payload.title.strip() or "未命名转盘",
    options_json=options,
    style=payload.style or "wheel",
    is_shared=is_shared,
    color_seed=payload.color_seed,
  )
  session.add(preset)
  await session.commit()
  await session.refresh(preset)

  response = decision_schema.DecisionPresetResponse(
    id=preset.id,
    title=preset.title,
    options=preset.options_json,
    style=preset.style,
    is_shared=preset.is_shared,
    color_seed=preset.color_seed,
    usage_count=preset.usage_count,
    last_used_at=preset.last_used_at,
    last_result=preset.last_result,
    created_at=preset.created_at,
    updated_at=preset.updated_at,
  )

  return success_response(response.model_dump(mode='json'))


@router.put('/{preset_id}', summary="更新随机转盘")
async def update_preset(
  preset_id: int,
  payload: decision_schema.DecisionPresetUpdate,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
):
  preset = await session.get(DecisionPreset, preset_id)
  preset = _ensure_access(preset, current_user)

  if payload.title is not None:
    preset.title = payload.title.strip() or preset.title

  if payload.style is not None:
    preset.style = payload.style

  if payload.color_seed is not None:
    preset.color_seed = payload.color_seed

  if payload.is_shared is not None:
    if payload.is_shared and current_user.active_relationship_id is not None:
      preset.is_shared = True
      preset.relationship_id = current_user.active_relationship_id
    elif not payload.is_shared:
      preset.is_shared = False
      preset.relationship_id = None

  if payload.options is not None:
    options = _normalize_options(payload.options)
    if len(options) < 2:
      raise HTTPException(status_code=422, detail="请至少提供两个不同的选项")
    if len(options) > 8:
      raise HTTPException(status_code=422, detail="选项数量最多 8 个")
    preset.options_json = options

  session.add(preset)
  await session.commit()
  await session.refresh(preset)

  response = decision_schema.DecisionPresetResponse(
    id=preset.id,
    title=preset.title,
    options=preset.options_json,
    style=preset.style,
    is_shared=preset.is_shared,
    color_seed=preset.color_seed,
    usage_count=preset.usage_count,
    last_used_at=preset.last_used_at,
    last_result=preset.last_result,
    created_at=preset.created_at,
    updated_at=preset.updated_at,
  )
  return success_response(response.model_dump(mode='json'))


@router.delete('/{preset_id}', summary="删除随机转盘")
async def delete_preset(
  preset_id: int,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
):
  preset = await session.get(DecisionPreset, preset_id)
  preset = _ensure_access(preset, current_user)
  preset.deleted_at = datetime.now(timezone.utc)
  session.add(preset)
  await session.commit()
  return success_response()


def _spin_from_options(options: list[str]) -> tuple[int, str]:
  if len(options) < 2:
    raise HTTPException(status_code=422, detail="请至少提供两个选项")
  index = sys_random.randrange(0, len(options))
  return index, options[index]


@router.post('/quick-spin', summary="临时随机一次（不保存）")
async def quick_spin(
  payload: decision_schema.DecisionSpinRequest,
  current_user: User = Depends(get_current_user),
):
  options = _normalize_options(payload.options)
  idx, value = _spin_from_options(options)
  result = decision_schema.DecisionSpinResult(
    title=(payload.title or "灵感小转盘").strip() or "灵感小转盘",
    options=options,
    selected_index=idx,
    selected_value=value,
    preset_id=None,
  )
  return success_response(result.model_dump(mode='json'))


@router.post('/{preset_id}/spin', summary="使用已保存转盘随机一次")
async def spin_saved(
  preset_id: int,
  current_user: User = Depends(get_current_user),
  session: AsyncSession = Depends(get_db),
):
  preset = await session.get(DecisionPreset, preset_id)
  preset = _ensure_access(preset, current_user)
  options = preset.options_json or []
  idx, value = _spin_from_options(options)

  preset.usage_count = (preset.usage_count or 0) + 1
  preset.last_used_at = datetime.now(timezone.utc)
  preset.last_result = value
  session.add(preset)
  await session.commit()
  await session.refresh(preset)

  result = decision_schema.DecisionSpinResult(
    title=preset.title,
    options=options,
    selected_index=idx,
    selected_value=value,
    preset_id=preset.id,
  )
  return success_response(result.model_dump(mode='json'))
